﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.IntelliTrace;
using System.Collections.Specialized;
using System.Globalization;

namespace Microsoft.VisualStudio.Samples
{
    public class ThreadChainConsoleWriter : ChainConsoleWriter, ThreadChainHandler
    {
        public ThreadChainConsoleWriter(Writer writer)
        {
            Writer = writer;
        }

        private Writer Writer { get; set; }
        public IntelliTraceProcess Process { get; set; }

        public void ExceptionSearchFunctionEnterEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            ExceptionEvent(ev);
        }

        public void ExceptionSearchFunctionExitEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            ExceptionEvent(ev);
        }

        public void ExceptionSearchFilterEnterEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            ExceptionEvent(ev);
        }

        public void ExceptionSearchFilterExitEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            ExceptionEvent(ev);
        }

        public void ExceptionSearchCatchFoundEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            ExceptionEvent(ev);
        }

        public void ExceptionUnwindFunctionEnterEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            ExceptionEvent(ev);
        }

        public void ExceptionUnwindFunctionExitEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            ExceptionEvent(ev);
        }

        public void ExceptionUnwindFinallyEnterEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            ExceptionEvent(ev);
        }

        public void ExceptionUnwindFinallyExitEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            ExceptionEvent(ev);
        }

        public void ExceptionCatchEnterEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            ExceptionEvent(ev);
        }

        public void ExceptionCatchExitEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            ExceptionEvent(ev);
        }

        public void MethodEnterEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            Writer.WriteLine(FormatSeparator(ev));
            ResolvedMethodEnterEvent methodEnterEvent = new ResolvedMethodEnterEvent(Process, ev as MethodEnterEvent);

            NameValueCollection eventProperties = new NameValueCollection();
            eventProperties.Add("Ordinal", methodEnterEvent.MethodEnterEvent.Ordinal.ToString(CultureInfo.CurrentCulture));
            eventProperties.Add("Name", FormatFullMethodName(methodEnterEvent.Method));
            IList<IDataElement> parameters = methodEnterEvent.GetParameters();
            eventProperties.Add("Parameters", string.Format(CultureInfo.CurrentCulture, "{0} parameters", parameters.Count));

            DumpProperties(eventProperties);

            DumpDataElements(parameters, 0);
        }

        public void MethodExitEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            Writer.WriteLine(FormatSeparator(ev));
            ResolvedMethodExitEvent methodExitEvent = new ResolvedMethodExitEvent(Process, ev as MethodExitEvent);

            NameValueCollection eventProperties = new NameValueCollection();
            eventProperties.Add("Ordinal", methodExitEvent.MethodExitEvent.Ordinal.ToString(CultureInfo.CurrentCulture));
            eventProperties.Add("Name", FormatFullMethodName(methodExitEvent.Method));
            IList<IDataElement> outputs = methodExitEvent.GetOutputs();
            eventProperties.Add("Outputs", string.Format(CultureInfo.CurrentCulture, "{0} outputs", outputs.Count));

            DumpProperties(eventProperties);
            DumpDataElements(outputs, 0);

            IDataElement returnValue = methodExitEvent.GetReturnValue();
            if (returnValue != null)
            {
                List<IDataElement> returnValues = new List<IDataElement>();
                returnValues.Add(returnValue);

                Writer.WriteLine(s_nameValueFormat, "Return value", string.Empty);
                DumpDataElements(returnValues, 0);
            }
        }

        public void CallSiteEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            Writer.WriteLine(FormatSeparator(ev));
            ResolvedCallSiteEvent callSiteEvent = new ResolvedCallSiteEvent(Process, ev as CallSiteEvent);

            NameValueCollection eventProperties = new NameValueCollection();
            eventProperties.Add("Ordinal", callSiteEvent.CallSiteEvent.Ordinal.ToString(CultureInfo.CurrentCulture));
            eventProperties.Add("IL offset", callSiteEvent.CallSiteEvent.Offset.ToString(CultureInfo.CurrentCulture));
            eventProperties.Add("Calling method", FormatFullMethodName(callSiteEvent.CallerMethod));
            IntelliTraceSourceLocation location = GetSourceLocation(callSiteEvent.CallSiteEvent.CallerMethodToken, callSiteEvent.CallSiteEvent.Offset);
            eventProperties.Add("Calling method location", FormatSourceLocation(location));
            eventProperties.Add("Called method", FormatFullMethodName(callSiteEvent.CalleeMethod));
            location = GetSourceLocation(callSiteEvent.CallSiteEvent.CalleeMethodToken, 0);
            eventProperties.Add("Called method location", FormatSourceLocation(location));

            DumpProperties(eventProperties);
        }

        public void ExceptionThrownEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            Writer.WriteLine(FormatSeparator(ev));
            ResolvedExceptionThrownEvent exceptionThrownEvent = new ResolvedExceptionThrownEvent(Process, ev as ExceptionThrownEvent);

            NameValueCollection eventProperties = new NameValueCollection();
            eventProperties.Add("Ordinal", exceptionThrownEvent.ExceptionThrownEvent.Ordinal.ToString(CultureInfo.CurrentCulture));
            eventProperties.Add("Method", FormatFullMethodName(exceptionThrownEvent.Method));
            IList<IDataElement> data = exceptionThrownEvent.GetData();
            eventProperties.Add("Exception data", string.Empty);

            DumpProperties(eventProperties);

            DumpDataElements(data, 0);
        }

        public void ExceptionEvent(IntelliTrace.IntelliTraceEvent ev)
        {
            Writer.WriteLine(FormatSeparator(ev));
            ResolvedExceptionEvent exceptionEvent = new ResolvedExceptionEvent(Process, ev as ExceptionEvent);

            NameValueCollection eventProperties = new NameValueCollection();
            eventProperties.Add("Ordinal", exceptionEvent.ExceptionEvent.Ordinal.ToString(CultureInfo.CurrentCulture));
            eventProperties.Add("Method", FormatFullMethodName(exceptionEvent.Method));

            DumpProperties(eventProperties);
        }


    }
}
